package com.ctl.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ctl.dto.*;
import com.ctl.entity.*;
import com.ctl.service.*;
import com.ctl.sign.SignPrefig;
import com.ctl.util.OssUtils;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.errors.*;
import org.apache.commons.lang.RandomStringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;

@RestController
//@RequestMapping("/tokens")
public class UserController {
    @Autowired
    private UserService service;
    @Autowired
    private RedisTemplate redisTemplate;
    //返回根据id返回用户信息
    @GetMapping("/userByuid")
    public User getUser(@RequestParam("uid") Integer uid){
       return service.getById(uid);
    }
    //返回用户是否想回关注
    @GetMapping("/isFollow")
    public Boolean getIsFollow(@RequestParam("uid") Integer uid,@RequestParam("followId") Integer followId){
       return followingService.isFollowing(uid,followId);
    }
    @Autowired
    private PlayedService playedService;
    //视频播放
    @PutMapping("/user/played/{video_id}")
    public void playedConut(@PathVariable String video_id,String token){
        //将播放次数存入 redis缓存中，自增 1
        redisTemplate.opsForValue().increment(SignPrefig.VIDEO_PLAYED_COUNT+video_id);
        //判断是否登录
        if (token!=null){
            //获取登录用户信息
            User user = (User) redisTemplate.opsForValue().get(token);
            Played played = new Played();
            played.setUid(user.getId());
            played.setCreatedAt(new Date());
            played.setUpdatedAt(new Date());
            played.setVideoId(Integer.parseInt(video_id));
            //添加视频播放历史记录
            playedService.save(played);
        }
    }
    //视频播放历史
    @GetMapping("/user/played")
    public List<VideosDTO> userPlayed( String token,@RequestParam(defaultValue = "1") Integer page,
                            @RequestParam(defaultValue = "10")Integer per_page){
        ArrayList<VideosDTO> videosDTOS = new ArrayList<>();
        //获取用户登录信息
        User user = (User) redisTemplate.opsForValue().get(token);
        //分页查询用户视频播放历史
        Page<Played> tPage = new Page<>(page,per_page);
        QueryWrapper<Played> playedQueryWrapper = new QueryWrapper<>();
        playedQueryWrapper.eq("uid",user.getId());
        //获取视频信息
        playedService.page(tPage,playedQueryWrapper);
        List<Played> playeds = tPage.getRecords();
        for (Played played : playeds) {
            VideosDTO videosDTO = new VideosDTO();
            Video video = videoService.getById(played.getVideoId());
            BeanUtils.copyProperties(video,videosDTO);
            User userv = service.getById(video.getUid());
            videosDTO.setUploader(userv.getName());
            videosDTOS.add(videosDTO);
        }
        return videosDTOS;
    }

    @Autowired
    private FavoriteService favoriteService;
    //收藏列表
    @GetMapping("/user/favorites")
    public List<VideosDTO> favoritePage(String token,
                                        @RequestParam(defaultValue = "1") Integer page,
                                        @RequestParam(defaultValue = "10")Integer per_page){
        //获取登录用户信息
        User user = (User) redisTemplate.opsForValue().get(token);
        List<VideosDTO> videosDTOS = new ArrayList<>();
        //获取收藏列表信息
        Page<Favorite> pages = new Page<>(page, per_page);
        QueryWrapper<Favorite> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("uid",user.getId());
         favoriteService.page(pages,queryWrapper);
        List<Favorite> favorites = pages.getRecords();
        for (Favorite favorite : favorites) {
            VideosDTO videosDTO = new VideosDTO();
            Video video = videoService.getById(favorite.getVideoId());
            //获取视频分类
            Category category = categoryService.getById(video.getCategoryId());
            video.setCategory(category.getName());
            BeanUtils.copyProperties(video,videosDTO);
            //获取视频 up主
            User vuser = service.getById(video.getUid());
            videosDTO.setUploader(vuser.getName());
            //todo:获取视频的点赞数

            videosDTOS.add(videosDTO);
        }
        return videosDTOS;
    }
    //视频收藏
    @PutMapping("/user/favorites/{video_id}")
    public void videoFavorites(@PathVariable Integer video_id,String token){
        //获取登录用户信息
        User useToken = (User) redisTemplate.opsForValue().get(token);
        Favorite favorite = new Favorite();
        favorite.setUid(useToken.getId());
        favorite.setVideoId(video_id);
        favorite.setCreatedAt(new Date());
        favorite.setUpdatedAt(new Date());
        favoriteService.save(favorite);
    }
    //取消视频收藏
    @DeleteMapping("/user/favorites/{video_id}")
    public void delFavorite(@PathVariable Integer video_id,String token){
        User use = (User) redisTemplate.opsForValue().get(token);
        QueryWrapper<Favorite> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("video_id", video_id)
                        .eq("uid",use.getId());
       favoriteService.remove(queryWrapper);
    }
    @GetMapping("/user")
    public UserDTO getUser(String token){
        User user = (User) redisTemplate.opsForValue().get(token);
        if (user==null){
            throw new RuntimeException("请先进行登录！");
        }
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(user,userDTO);
        return userDTO;
    }
    //注入minio客户端对象参数
    @Autowired
    private MinioClient minioClient;
    @Value("${minio.endpoint}")//minion客户端 ip地址
    private String endpoint;
    @Value("${minio.bucketName}")//minion存储文件 桶名称
    private String bucketName;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private VideoService videoService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private FeedService feedService;

    @PostMapping("/user/videos")    //上传视频
    public FileDTO uploadFile(MultipartFile file, String title, String token,
                              String intro, Integer category_id)
            throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        //获取上传的登录用户信息
        User user = (User) redisTemplate.opsForValue().get(token);
        System.out.println("user = " + user);
        //获取上传文件名
        String filename = file.getOriginalFilename();
        //上传存储文件随机名称
        String xFileName = UUID.randomUUID().toString().substring(0,4)+filename;
        FileDTO fileDTO = new FileDTO();
        //获取文件输入流对象
        InputStream inputIO = null;
        try {
            inputIO = file.getInputStream();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //获取当前时间作为 桶的子目录
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = sdf.format(date);
//        //上传至minio客户端
//        minioClient.putObject(PutObjectArgs.builder()
//                .bucket(bucketName)//存储文件 桶名称
//                .object("/"+dateStr+"/"+xFileName)//上传文件名称
//                .stream(inputIO,file.getSize(),-1)//流传输大小
//                .contentType(file.getContentType())//文件上传类型
//                .build());
        //上传至阿里云 OSS
        String path = OssUtils.upload(inputIO, dateStr, xFileName);
        //存进数据库
        Video video = new Video();
        video.setTitle(title);
        video.setIntro(intro);
        video.setCategoryId(category_id);
//        video.setCover(endpoint+"/"+bucketName+"/"+dateStr+"/"+xFileName);
//        video.setLink(endpoint+"/"+bucketName+"/"+dateStr+"/"+xFileName);
        video.setLink(path);
        video.setCover(path);
        video.setUid(user.getId());
        video.setCreatedAt(new Date());
        video.setUpdatedAt(new Date());
        videoService.save(video);
        //向 mq发消息
        rabbitTemplate.convertAndSend("videos",video);
        //生成用户动态
        Feed feed = new Feed();
        feed.setUserId(user.getId());
        feed.setCreatedAt(new Date());
        feed.setUpdatedAt(new Date());
        feed.setContent(video.getIntro());
        feed.setType("video");
        feedService.save(feed);
        BeanUtils.copyProperties(video,fileDTO);
        QueryWrapper<Category> wrapper = new QueryWrapper<>();
        wrapper.eq("id",category_id);
        Category category = categoryService.getOne(wrapper);
        fileDTO.setCategory(category.getName());
        return fileDTO;

    }
    @PatchMapping("/user")
    public UserDTO upUser(String token,@RequestBody UserDTO user,String captcha){
        //获取登录用户的信息
        User tokenUser = (User) redisTemplate.opsForValue().get(token);
        System.out.println("user = " + user);

        //判断登录号码是否修改
        if (!tokenUser.getPhone().equals(user.getPhone())||user.getPhone()==null){
                String code = (String) redisTemplate.opsForValue().get(SignPrefig.PHONE_CODE + user.getPhone());
            System.out.println("号码已修改。。。");
                if (!code.equals(captcha)){
                    throw new RuntimeException("验证码输入错误，请重新输入！");
                }
        }
        BeanUtils.copyProperties(user,tokenUser);
        System.out.println("tokenUser = " + tokenUser);
        service.updateById(tokenUser);
        UserDTO userDTO = new UserDTO();
        BeanUtils.copyProperties(tokenUser,userDTO);
        return userDTO;
    }
    //发布动态
    @PostMapping("/user/feeds")
    public void uploadFeeds(@RequestParam("file[]") MultipartFile[] files,String content,String token)
            throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        //获取发表动态的用户信息
        User use = (User) redisTemplate.opsForValue().get(token);
        //创建动态对象
        Feed feed = new Feed();
        feed.setContent(content);
        feed.setVideoId(null);
        feed.setUserId(use.getId());
        feed.setUpdatedAt(new Date());
        feed.setCreatedAt(new Date());
        feed.setType("normal");
        System.out.println("files = " + files);
        //处理上传的动态图片
        if (files!=null){
            StringBuilder stringBuilder = new StringBuilder();
            for (MultipartFile file : files) {
                System.out.println("file = " + file);
                //获取上传文件名
                String filename = file.getOriginalFilename();
                //上传存储文件随机名称
                String xFileName = UUID.randomUUID().toString().substring(0,4)+filename;
                //获取文件输入流对象
                InputStream inputIO = null;
                try {
                    inputIO = file.getInputStream();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                //获取当前时间作为 桶的子目录
                Date date = new Date();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                String dateStr = sdf.format(date);
//                //上传至minio客户端
//                minioClient.putObject(PutObjectArgs.builder()
//                        .bucket(bucketName)//存储文件 桶名称
//                        .object("/"+dateStr+"/"+ xFileName)//上传文件名称
//                        .stream(inputIO,file.getSize(),-1)//流传输大小
//                        .contentType(file.getContentType())//文件上传类型
//                        .build());
                //上传至阿里云 OSS
                String path = OssUtils.upload(inputIO, dateStr, xFileName);
                //获取存储路径的信息
//                String url= endpoint+"/"+bucketName+"/"+dateStr+"/"+xFileName;
                stringBuilder.append(path+" ");
            }
            
            feed.setImages(stringBuilder.toString());
            feedService.save(feed);
        }
    }

    //视频点赞
    @PutMapping("/user/liked/{video_id}")
    public void likeds(String token,@PathVariable Integer video_id){
        //获取登录用户信息
        User user = (User) redisTemplate.opsForValue().get(token);
        //判断用户是否点过赞
        if (redisTemplate.opsForSet().isMember(SignPrefig.USER_LIKE_VIDEO + user.getId(), video_id)==false){
            //创建用户点赞视频 set集合 key 用户信息   value 视频id
            redisTemplate.opsForSet().add(SignPrefig.USER_LIKE_VIDEO+user.getId(),video_id);
            //统计视频被点赞次数 key 为视频id
            redisTemplate.opsForValue().increment(SignPrefig.VIDEO_LIKE_COUNT+video_id);
        }
        //视频点赞后，删除用户不喜欢的视频记录
        if(redisTemplate.opsForSet().isMember(SignPrefig.USER_DISLIKE_VIDEO + user.getId(), video_id)==true) {
            redisTemplate.opsForSet().remove(SignPrefig.USER_DISLIKE_VIDEO+user.getId(),video_id);
            //视频被取消点赞次数减一 key 为视频id
            Integer integer = (Integer) redisTemplate.opsForValue().get(SignPrefig.VIDEO_LIKE_COUNT + video_id);
            if (integer==0){
                redisTemplate.opsForValue().set(SignPrefig.VIDEO_LIKE_COUNT+video_id,0);
            }else {
                redisTemplate.opsForValue().decrement(SignPrefig.VIDEO_LIKE_COUNT+video_id);
            }

        }
    }
    //用户点击不喜欢
    @PutMapping("/user/disliked/{video_id}")
    public void dislikeds(String token,@PathVariable Integer video_id){
        //获取登录用户信息
        User user = (User) redisTemplate.opsForValue().get(token);
        //判断用户是否点过赞
        if (redisTemplate.opsForSet().isMember(SignPrefig.USER_DISLIKE_VIDEO + user.getId(), video_id)==false){
            //创建用户点赞视频 set集合 key 用户信息   value 视频id
            redisTemplate.opsForSet().add(SignPrefig.USER_DISLIKE_VIDEO+user.getId(),video_id);
            //统计视频被点赞次数 key 为视频id
            redisTemplate.opsForValue().increment(SignPrefig.VIDEO_DISLIKE_COUNT+video_id);
        }
        if (redisTemplate.opsForSet().isMember(SignPrefig.USER_DISLIKE_VIDEO + user.getId(), video_id)==true){
            //删除用户不喜欢视频 set集合 key 用户信息   value 视频id
            redisTemplate.opsForSet().remove(SignPrefig.USER_DISLIKE_VIDEO+user.getId(),video_id);
        }
        
       
    }
    //取消视频点赞
    @DeleteMapping("/user/liked/{video_id}")
    public void delLikeds(String token,@PathVariable Integer video_id){
        //获取登录用户信息
        User user = (User) redisTemplate.opsForValue().get(token);
        //判断用户是否点过赞
        if (redisTemplate.opsForSet().isMember(SignPrefig.USER_LIKE_VIDEO + user.getId(), video_id)==true){
            //删除用户点赞视频 set集合 key 用户信息   value 视频id
            redisTemplate.opsForSet().remove(SignPrefig.USER_LIKE_VIDEO+user.getId(),video_id);
            //视频被取消点赞次数减一 key 为视频id
            Integer integer = (Integer) redisTemplate.opsForValue().get(SignPrefig.VIDEO_LIKE_COUNT + video_id);
            if (integer==0){
                redisTemplate.opsForValue().set(SignPrefig.VIDEO_LIKE_COUNT+video_id,0);
            }else {
                redisTemplate.opsForValue().decrement(SignPrefig.VIDEO_LIKE_COUNT+video_id);
            }

        }
    }
    //取消不喜欢
    @DeleteMapping("/user/disliked/{video_id}")
    public void deldisLikeds(String token,@PathVariable Integer video_id){
        //获取登录用户信息
        User user = (User) redisTemplate.opsForValue().get(token);
        //判断用户是否点过赞
        if (redisTemplate.opsForSet().isMember(SignPrefig.USER_DISLIKE_VIDEO+ user.getId(), video_id)==true){
            //删除用户不喜欢视频 set集合 key 用户信息   value 视频id
            redisTemplate.opsForSet().remove(SignPrefig.USER_DISLIKE_VIDEO+user.getId(),video_id);
            //视频被取消不喜欢次数减一 key 为视频id
            redisTemplate.opsForValue().decrement(SignPrefig.VIDEO_DISLIKE_COUNT+video_id);
        }
    }

    @DeleteMapping("/token")
    public void delUser(String token){
        redisTemplate.delete(token);
    }
    @Autowired
    private FollowingService followingService;
    @GetMapping("/users/{user_id}")
    public UserFollowingDTO getUserId(@PathVariable Integer user_id, String token){
        UserFollowingDTO followingDTO = new UserFollowingDTO();
        User user = service.getById(user_id);
        if (token==null){   //判断用户是否登录
            followingDTO.setFollowed(false);
        }else {
            User redisUser = (User) redisTemplate.opsForValue().get(SignPrefig.USER_TOKEN + token);
            followingService.isFollowing(redisUser.getId(),user_id);
            }
        BeanUtils.copyProperties(user,followingDTO);
        return followingDTO;
    }
    @PostMapping("/tokens")
    public Map<String,String> login(@RequestBody MsgDTO msg){
        String token=null;
        HashMap<String, String> map = new HashMap<>();
        //1. 获取手机跟验证码
        String phone = msg.getPhone();
        String captcha = msg.getCaptcha();
        //2. 校验该手机号是否发送验证码
        if (!redisTemplate.hasKey(SignPrefig.PHONE_CODE+phone)){
            throw new RuntimeException("请重新获取验证码！");
        }
        //3. 校验输入的验证码是否一致
        String cade = (String) redisTemplate.opsForValue().get(SignPrefig.PHONE_CODE + phone);
        if (!captcha.equals(cade)){
            throw new RuntimeException("验证码输入错误！");
        }
        //4. 更新数据信息
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone",phone);
        User user = service.getOne(queryWrapper);
        if (ObjectUtils.isEmpty(user)){ //如果数据没有该用户，则进行注册
            user=new User();
            user.setPhone(phone);
            user.setCreatedAt(new Date());
            user.setUpdatedAt(new Date());
            user.setFollowersCount(0);
            user.setFollowingCount(0);
            user.setIntro("");
            String xname = RandomStringUtils.randomNumeric(5);
            user.setName(xname+"用户");
            user.setPhoneLinked(1);
            user.setWechatLinked(0);
            List<String> images=new ArrayList<>();
            int i = new Random().nextInt(2);
            images.add("https://s1.ax1x.com/2023/02/27/pp97KWn.jpg");
            images.add("https://s1.ax1x.com/2023/02/27/pp9bIIg.png");
            user.setAvatar(images.get(i));
            service.save(user);
        }
        String uuid = UUID.randomUUID().toString();
        token= SignPrefig.USER_TOKEN+uuid;
        redisTemplate.opsForValue().set(token,user,2, TimeUnit.HOURS);
        map.put("token",token);
        return map;
    }


}
